/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.fjala.softure.tree.hashTree;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.fjala.softure.tree.Node;

/**
 *
 * @author f3r
 */
public class BinaryHashNode<T> implements Node<T> {

    /**
     * Node value
     */
    private T value;

    /**
     * Hash Code from the Value
     */
    private int hashCode;

    /**
     * Parent of a Node
     */
    private BinaryHashNode<T> parent;

    /**
     * Left Child of a Node
     */
    private BinaryHashNode<T> left;

    /**
     * Right Child of a Node
     */
    private BinaryHashNode<T> right;

    /**
     * Map to handle children
     */
    private Map<Integer, Node<T>> map;

    /**
     * Initialize the attributes and set a value
     *
     * @param v Value to be set
     */
    public BinaryHashNode(T v) {
        value = v;
        hashCode = v.hashCode();
        map = new HashMap<Integer, Node<T>>();
    }

    @Override
    public T getData() {
        return value;
    }

    @Override
    public List<Node<T>> getChildren() {
        List<Node<T>> res = new ArrayList<Node<T>>();

        if(left != null) {
            res.add(left);
        }

        if(right != null) {
            res.add(right);
        }

        return res;
    }

    /**
     * Get all children from a specific node
     *
     * @param node Node to count its children
     *
     * @return All children of an specific node
     */
    public List<Node<T>> getAllChildren(BinaryHashNode<T> node) {
        List<Node<T>> res = new ArrayList<Node<T>>();
        List<Node<T>> a = null;
        List<Node<T>> b = null;
        List<Node<T>> c = null;

        if(node != null) {
            a = node.getChildren();
            res.addAll(a);

            if(node.getLeft() != null) {
                b = node.getAllChildren(node.getLeft());
                res.addAll(b);
            }

            if(node.getRight() != null) {
                c = node.getAllChildren(node.getRight());
                res.addAll(c);
            }
        }

        return res;
    }

    @Override
    public Node<T> getParent() {
        return parent;
    }

    @Override
    public boolean hasChildren() {
        return left != null;
    }

    @Override
    public void addChild(Node<T> child) {
        if(left == null) {
            this.setLeft((BinaryHashNode<T>) child);
            addNewElementToParent(this, child);
        } else if(right == null) {
            this.setRight((BinaryHashNode<T>) child);
            addNewElementToParent(this, child);
        }
    }

    /**
     * Add values to all parents map recursively
     *
     * @param parent Parent to be added
     * @param newNode Node to be added
     */
    private void addNewElementToParent(BinaryHashNode<T> parent, Node<T> newNode) {
        if(parent != null) {
            parent.getMap().put(newNode.getData().hashCode(), newNode);
            addNewElementToParent((BinaryHashNode<T>) parent.getParent(), newNode);
        }
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public int getHashCode() {
        return hashCode;
    }

    public BinaryHashNode<T> getLeft() {
        return left;
    }

    public void setLeft(BinaryHashNode<T> left) {
        this.left = left;
    }

    public BinaryHashNode<T> getRight() {
        return right;
    }

    public void setRight(BinaryHashNode<T> right) {
        this.right = right;
    }

    public Map<Integer, Node<T>> getMap() {
        return map;
    }

    @Override
    public void setData(T t) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void setParent(Node<T> parent) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void removeChild(Node<T> child) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public int getChildCount() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
